/*
 * @Description: request请求
 * @Author: xinqiao lxq1990.0716@qq.com
 * @Date: 2023-03-27
 * @LastEditors: xinqiao lxq1990.0716@qq.com
 * @LastEditTime: 2025-03-25
 */

import { message } from 'ant-design-vue'
import axios, { AxiosError, AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'

import { ExceptionEnum } from '/@/enums/exceptionEnum'
import { HttpCodeEnum } from '/@/enums/httpEnum'
import { checkWhiteRoute, goLogin } from '/@/router'
import { getToken } from '/@/storage'
import { useExceptionStore } from '/@/store/modules/exception'
import { getTargetCookie } from '/@/utils/getCookie'
import { mock, needMock } from '/mock/mock'

import LR from '../assets/js/report-released-1.2.0'
import { MESSAGE_KEY } from '../enums/commonEnum'

type AxiosConfig = AxiosResponse['config']
type ResponseType = Omit<AxiosResponse, 'config'> & {
  config: AxiosConfig
}

const httpConfig = {
  baseURL: import.meta.env.VITE_BASE_API_PATH,
  timeout: 10000,
  withCredentials: true,
  headers: {
    'Content-Type': 'application/json',
  },
}

LR.init({
  namespace: 'ssc_website',
  appKey: '7a2a6182c10840e18c31c4e01512771e',
  appVersion: '1.0.0',
  deviceKey: null,
  userKey: '1',
  clientId: '7a2a6182c10840e18c31c4e01512771e',
  subscribeId: '8517c0ac01b04fb689d58647129d8759',
})

/** 重新登陆状态码列表 */
const RELOGIN_LIST = [HttpCodeEnum.ERROR_TOKEN_INVALID, HttpCodeEnum.ERROR_NO_LOGIN, HttpCodeEnum.ERROR_OTHER_LOGIN]

class RequestHttp {
  instance: AxiosInstance
  config: IRequestConfig

  public constructor(axiosConfig: AxiosRequestConfig) {
    this.instance = axios.create(axiosConfig)
    this.config = {
      errTip: true,
    }

    // 请求拦截器
    this.instance.interceptors.request.use(
      (req: AxiosConfig) => {
        const token = getToken()
        /** 后台登录跳转-从本地storage获取token */
        if (token) {
          req.headers['Authorization'] = token
        } else {
          /** zeus平台跳转-从cookie获取token */
          req.headers['Authorization'] = getTargetCookie('sessionId')
        }
        // LR.report('_VIEW', {
        //   crashInfo: {
        //     crashType: 'anr',
        //     crashName: req.params,
        //     crashTime: Date.now(),
        //   },
        // })
        const platformCode = import.meta.env.VITE_GLOB_PLATFORMCODE
        if (['post', 'put'].includes(req.method || '')) {
          req.data['platformCode'] = platformCode
        } else if (['get', 'delete'].includes(req.method || '')) {
          req.params['platformCode'] = platformCode
        }
        return req
      },
      (error: AxiosError) => {
        return Promise.reject(error)
      },
    )

    // 响应拦截器
    this.instance.interceptors.response.use(
      (res: ResponseType) => {
        const { data, config } = res
        if (config?.responseType === 'text') {
          return Promise.resolve({ responseCode: 100000000, responseData: data })
        }
        if (data.code === 0) {
          return Promise.resolve({ responseCode: 100000000, responseData: data })
        }
        const { responseCode, responseMessage } = data
        if (responseCode === HttpCodeEnum.SUCCESS) {
          return Promise.resolve(data)
        }
        if (RELOGIN_LIST.includes(responseCode)) {
          if (!checkWhiteRoute()) goLogin()
          return Promise.resolve(data)
        }
        if (this.config.errTip) message.error({ content: responseMessage, key: MESSAGE_KEY })
        return Promise.resolve(data)
      },
      (error) => {
        if (error.code === 'ECONNABORTED') {
          message.error({ content: '连接超时，请重试', key: MESSAGE_KEY })
          return Promise.reject(error)
        }
        const { responseCode, responseMessage, error: errText } = error.response.data
        if (RELOGIN_LIST.includes(responseCode)) {
          if (!checkWhiteRoute()) goLogin()
          return Promise.reject(error)
        }
        message.error({ content: responseMessage || errText || error, key: MESSAGE_KEY })
        const errMsg = error?.response?.data?.msg || error?.response?.data?.message || '未知错误，请重试'
        if (!error.config || error.config.isErr) {
          message.destroy()
          const exceptionStore = useExceptionStore()
          exceptionStore.status = ExceptionEnum.ERROR
        }
        error.message = errMsg
        return Promise.reject(error)
      },
    )
  }

  async get<T>(url: string, params: object = {}, config?: IRequestConfig): Promise<T> {
    if (needMock(url)) return (await mock(url)) as T
    this.config = { ...this.config, ...config }
    return await this.instance.get(url, { params })
  }

  async post<T, D = any>(url: string, data: D, config?: IRequestConfig): Promise<T> {
    if (needMock(url)) return (await mock(url)) as T
    this.config = { ...this.config, ...config }
    return await this.instance.post(url, data)
  }

  async put<T, D = any>(url: string, data: D, config?: IRequestConfig): Promise<T> {
    if (needMock(url)) return (await mock(url)) as T
    this.config = { ...this.config, ...config }
    return await this.instance.put(url, new URLSearchParams(data as Record<string, string>), {
      headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    })
  }

  async delete<T, D = any>(url: string, params: D, config?: IRequestConfig): Promise<T> {
    if (needMock(url)) return (await mock(url)) as T
    this.config = { ...this.config, ...config }
    return await this.instance.delete(url, { params })
  }

  async postFormDataProxy<T, D = any>(url: string, data: D, config?: IRequestConfig): Promise<any> {
    this.config = { ...this.config, ...config }
    return await this.instance.post(url, data, { headers: { 'Content-Type': 'multipart/form-data' } })
  }

  async downTxt<T>(url: string, params: object = {}, config?: IRequestConfig): Promise<T> {
    this.config = { ...this.config, ...config }
    return await this.instance.get(url, { params, responseType: 'text' })
  }
}

export default new RequestHttp(httpConfig)
